package org.example.dao;

import org.example.annotation.TableId;
import org.example.utils.JDBCUtils;
import org.example.wrapper.QueryWrapper;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class BaseDAO<T,K> {
    private final Class<T> CLASS;
    private final String PLACE_HOLDER;

    private final Field[] FIELDS;
    private final String FIELD_NAMES;
    private final String TABLE_NAME;
    private final String ID_NAME;
    private final String COLUMNS_KEY_VALUE;
    private final String UPDATE_COLUMNS_KEY_VALUE;

    {
        ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
        CLASS = (Class<T>) genericSuperclass.getActualTypeArguments()[0]; //获取了父类的泛型参数
        //获取表名
        TABLE_NAME = CLASS.getSimpleName().toLowerCase();
        //获取对象
        try {
            Constructor<T> constructor = CLASS.getConstructor();
            Object o = constructor.newInstance();
            //获取列名数组
            FIELDS = CLASS.getDeclaredFields();
            //初始化id名字
            if (CLASS.isAnnotationPresent(TableId.class)){
                TableId annotation = (TableId) CLASS.getAnnotation(TableId.class);
                ID_NAME = annotation.value();
            }else {
                ID_NAME = "id";
            }
            StringBuilder fieldNames = new StringBuilder();
            StringBuilder placeHolders = new StringBuilder();
            StringBuilder columnsKeyValue = new StringBuilder();
            StringBuilder updateColumnsKeyValue = new StringBuilder();



            //初始化占位符
            for (Field field : FIELDS) {
                field.setAccessible(true);
                fieldNames.append(field.getName()).append(",");
                placeHolders.append("?,");
                columnsKeyValue.append(field.getName()).append("=").append("?").append(",");
                if (!field.isAnnotationPresent(TableId.class)){
                    updateColumnsKeyValue.append(field.getName()).append("=").append("?").append(",");
                }
            }
            placeHolders.deleteCharAt(placeHolders.length() - 1);
            fieldNames.deleteCharAt(fieldNames.length() - 1);
            columnsKeyValue.deleteCharAt(columnsKeyValue.length() - 1);
            updateColumnsKeyValue.deleteCharAt(updateColumnsKeyValue.length() - 1);
            PLACE_HOLDER = String.valueOf(placeHolders);
            FIELD_NAMES = String.valueOf(fieldNames);
            //初始化全属性键值对
            COLUMNS_KEY_VALUE = String.valueOf(columnsKeyValue);
            //初始化按条件更新全属性键值对
            UPDATE_COLUMNS_KEY_VALUE = String.valueOf(updateColumnsKeyValue);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public boolean insert(T t) {
        try (Connection connection = JDBCUtils.getConnection()) {
            String str = String.format("INSERT INTO %s (%S) VALUES (%S)", TABLE_NAME, FIELD_NAMES, PLACE_HOLDER);
            PreparedStatement preparedStatement = connection.prepareStatement(str);
            for (int i = 0; i < FIELDS.length; i++) {
                preparedStatement.setObject(i + 1, FIELDS[i].get(t));
            }
            System.out.println(str);
            return preparedStatement.executeUpdate() == 1;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public T selectById(T t, K id){
        try (Connection connection = JDBCUtils.getConnection()) {
            String str = String.format("SELECT %s FROM %s WHERE %s = ?", FIELD_NAMES,TABLE_NAME,ID_NAME);
            PreparedStatement preparedStatement = connection.prepareStatement(str);
            preparedStatement.setObject(1,id);
            ResultSet resultSet = preparedStatement.executeQuery();
            if (resultSet.next()){
                for (Field declaredField : CLASS.getDeclaredFields()) {
                    declaredField.setAccessible(true);
                    declaredField.set(t,resultSet.getObject(declaredField.getName()));
                }
            }
            return t;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public boolean updateById(T t, K id){
        try (Connection connection = JDBCUtils.getConnection()) {
            String str = String.format("UPDATE %s SET %s WHERE %s = ?", TABLE_NAME,COLUMNS_KEY_VALUE,ID_NAME);
            PreparedStatement preparedStatement = connection.prepareStatement(str);
            for (int i = 0; i < FIELDS.length; i++) {
                preparedStatement.setObject(i + 1, FIELDS[i].get(t));
            }
            preparedStatement.setObject(FIELDS.length + 1, id);
            System.out.println(str);
            return preparedStatement.executeUpdate() == 1;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public boolean deleteById(K id){
        try (Connection connection = JDBCUtils.getConnection()) {
            String str = String.format("DELETE FROM %s WHERE %s = ?", TABLE_NAME,ID_NAME);
            PreparedStatement preparedStatement = connection.prepareStatement(str);
            preparedStatement.setObject(1, id);
            return preparedStatement.executeUpdate() == 1;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public List<T> selectByCondition(QueryWrapper queryWrapper){
        String condition = queryWrapper.getCondition();
        try (Connection connection = JDBCUtils.getConnection()) {
            String str = String.format("SELECT %s FROM %s WHERE 1=1 %s", FIELD_NAMES,TABLE_NAME,condition);
            PreparedStatement preparedStatement = connection.prepareStatement(str);
            System.out.println(str);
            ResultSet resultSet = preparedStatement.executeQuery();

            ArrayList<T> list = new ArrayList<>();
            while (resultSet.next()){
                T t = CLASS.getConstructor().newInstance();
                for (Field declaredField : CLASS.getDeclaredFields()) {
                    declaredField.setAccessible(true);
                    declaredField.set(t,resultSet.getObject(declaredField.getName()));
                }

                list.add(t);
            }
            return list;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public int updateByCondition(T t,QueryWrapper queryWrapper){
        String condition = queryWrapper.getCondition();
        try (Connection connection = JDBCUtils.getConnection()) {
            String str = String.format("UPDATE %s SET %s WHERE 1=1 %s", TABLE_NAME,UPDATE_COLUMNS_KEY_VALUE,condition);
            PreparedStatement preparedStatement = connection.prepareStatement(str);
            int i = 1;
            for (Field declaredField : t.getClass().getDeclaredFields()) {
                if (!declaredField.isAnnotationPresent(TableId.class)){
                    declaredField.setAccessible(true);
                    preparedStatement.setObject(i,declaredField.get(t));
                    i++;
                }

            }
            System.out.println(str);
            return preparedStatement.executeUpdate();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }




}
